<template>
    <div class="ts-form-table">
        <el-table :data="data" ref="table" :key="toggleIndex" width="400" border stripe
            :header-cell-style="{ 'color': '#000' }">
            <el-table-column type="index" width="50" fixed="left">
                <template #header>
                    <el-button v-if="!disabled&&!hideAdd" type="primary" size="small" :icon="Plus" circle @click="rowAdd">
                    </el-button>
                </template>
                <template #default="scope" v-if="!disabled">
                    <div class="ts-form-table-handle">
                        <span>{{ scope.$index + 1 }}</span>
                        <el-button type="danger" size="small" :icon="Delete" plain circle
                            @click="rowDel(scope.row, scope.$index)">
                        </el-button>
                    </div>
                </template>
            </el-table-column>
            <el-table-column v-if="edit" label="" width="58">
                <template #default="scope">
                    <el-tag @click="rowEdit(scope.row)">
                        <Edit style="width: 1em; height: 1em;" />
                    </el-tag>
                </template>
            </el-table-column>
            <el-table-column label="" width="58" v-if="dragSort">
                <template #default>
                    <el-tag class="move" style="cursor: move;">
                        <DCaret style="width: 1em; height: 1em;" />
                    </el-tag>
                </template>
            </el-table-column>
            <slot name="tableContent"></slot>
            <template #append>
                <slot name="append"></slot>
            </template>
            <template #empty>
                {{ placeholder }}
            </template>
        </el-table>
        <el-dialog v-model="dialogVisible" title="选择对话框" width="70%" append-to-body @open="open" destroy-on-close>
            <div style="display: flex;margin-bottom: 10px;">
                <el-checkbox @change="changeFuzzyQuery">模糊</el-checkbox>
                <el-button type="primary" @click="getTableData()" style="margin-left: 10px;">查 询</el-button>
            </div>
            <sc-form ref="formRef" :config="formConfig" v-model="formData" 
                style="margin-bottom: 5px;" @keyup.enter="search" :key="formKey"></sc-form>
            <el-table ref="multipleTableRef" :height="350" :data="dialogData" :lazy="lazy" :load="load" row-key="id"
                :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" @select="select" @select-all="selectAll">
                <el-table-column type="selection" width="45"></el-table-column>
                <template v-for="(item, index) in tableConfig" :key="index">
                    <el-table-column :prop="item.prop" :label="item.label" :width="flexWidth(item, dialogData)" />
                </template>
            </el-table>
            <div class="sc-table-select__page">
			<el-pagination small background layout="total,prev, pager, next" :total="tableRows" :page-size="pageSize"
				v-model:currentPage="currentPage" @current-change="getTableData"></el-pagination>
		</div>
        </el-dialog>
    </div>
</template>
<script setup>
import { Plus, Delete, DCaret, Edit } from '@element-plus/icons-vue';
import Sortable from 'sortablejs'
import { ref, reactive, onMounted, nextTick, watch } from 'vue'
import Api from '@/api/model/system'
import template from '@/utils/template';
import { deduplication } from '@/utils/arr.js'
const emit = defineEmits(['update:modelValue', 'deleteRow','selectRow'])
const props = defineProps({
    modelValue: { type: Array, default: () => [] },
    placeholder: { type: String, default: "暂无数据" },
    dragSort: { type: Boolean, default: false },
    disabled: { type: Boolean, default: false },
    hideAdd: { type: Boolean, default: false },
    edit: { type: Boolean, default: false },
    mapping: { type: Array, default: () => [] },//两个table的映射关系
    fileName: { type: String, default: '' },
    defineProps: { type: Object, default: () => { } },
    fieldMap: { type: Object, default: () => { } },
})
const data = ref(JSON.parse(JSON.stringify(props.modelValue || [])))
const templateData = ref(JSON.parse(JSON.stringify(props.modelValue || [])))
const multipleTableRef = ref(null)
const table = ref(null)
const dialogVisible = ref(false)
const formConfig = ref({})
const formData = ref({})
const lazy = ref(false)
const dialogData = ref([])
const tableConfig = ref([])
const currentPage = ref(1);
const pageSize = ref(20);
const toggleIndex = ref(0)
const tableRows = ref(0);
const fuzzyQuery = ref(false)
const formKey = ref(0)
onMounted(() => {
    if (props.dragSort) {
        rowDrop()
    }
})
//只watch一次的写法，作用：当组件的数据从后台获取时可用
const flag = watch(() => props.modelValue, (newValue) => {
    if (data.value.length == 0) {
        data.value = JSON.parse(JSON.stringify(newValue))
        templateData.value = JSON.parse(JSON.stringify(newValue))
    }
    if (newValue) {
        flag()
    }
}, {
    deep: true
})
watch(data, (newValue) => {
    emit('update:modelValue', newValue)
}, {
    deep: true
})
const rowDrop = () => {
    const tbody = table.value.$el.querySelector('.el-table__body-wrapper tbody')
    Sortable.create(tbody, {
        handle: ".move",
        animation: 300,
        ghostClass: "ghost",
        onEnd({ newIndex, oldIndex }) {
            const tableData = data.value
            const currRow = tableData.splice(oldIndex, 1)[0]
            tableData.splice(newIndex, 0, currRow)
            toggleIndex.value += 1
            nextTick(() => {
                rowDrop()
            })
        }
    })
}
const rowAdd = () => {
    dialogVisible.value = true
}
const changeFuzzyQuery = (val) => {
    fuzzyQuery.value = val
}
const search = (e) => {
    if (e.keyCode == 13) {
        getTableData()
    }
}
const flexWidth = (item, tableData, num = 0) => {
    if (item.flexColumnWidth == false || tableData.length == 0) {
        // 表格没数据不做处理
        if (item.width) {
            return item.width
        }
        return
    }
    let flexWidth = 0 // 初始化表格列宽
    let columnContent = '' // 占位最宽的内容
    let canvas = document.createElement('canvas')
    let context = canvas.getContext('2d')
    context.font = '14px Microsoft YaHei'
    if (item.prop === '' && item.title) {
        // 标题长内容少的，取标题的值,
        columnContent = item.title
    } else {
        // 获取该列中占位最宽的内容
        let index = 0
        for (let i = 0; i < tableData.length; i++) {
            const now_temp = tableData[i][item.prop] + ''
            const max_temp = tableData[index][item.prop] + ''
            const now_temp_w = context.measureText(now_temp).width
            const max_temp_w = context.measureText(max_temp).width
            if (now_temp_w > max_temp_w) {
                index = i
            }
        }
        columnContent = tableData[index][item.prop]
        // 比较占位最宽的值跟标题、标题为空的留出四个位置
        const column_w = context.measureText(columnContent).width
        const title_w = context.measureText(item.title).width
        if (column_w < title_w) {
            columnContent = item.title || '占位符呀'
        }
    }
    // 计算最宽内容的列宽
    let width = context.measureText(columnContent)
    flexWidth = width.width + 40 + num
    return flexWidth
}
const getInit = async () => {
    let params = {
        fileName: props.fileName
    }
    let res = await Api.report.selectCompanyList.post(params);
    if (res.code == 200) {
        formConfig.value = res.bean.form
        lazy.value = res.bean.table.lazy
        tableConfig.value = res.bean.table.columns;
    }
    tableConfig.value.forEach(item => {
        props.mapping.forEach(ele => {
            if (ele.value == item.prop) {
                item.prop = ele.label
            }
        })
    })
    getTableData()
}
const getTableData = async () => {
    dialogData.value = []
    let reportData = []
    var params = {
        fileName: props.fileName,
        fieldMap: formData.value,
        fuzzyQuery: fuzzyQuery.value,
        pageSize: pageSize.value,
        pageNo: currentPage.value, //1
    }
    var res = await Api.select.query.post(params);
    if (res.code == 200) {
        tableRows.value = res.rows;
        reportData = res.reportData;
    }
    dialogData.value = reportData.map(item => {
        props.mapping.forEach(ele => {
            item[ele.label] = item[ele.value]
            delete item[ele.value]
        })
        return item
    })
    nextTick(() => {
        if (data.value.length > 0) {
            data.value.forEach(row => {
                var setrow = dialogData.value.filter(item => item[props.defineProps.value] === row[props.defineProps.value])
                if (setrow.length > 0) {
                    multipleTableRef.value.toggleRowSelection(setrow[0], true);
                }
            })
        }
    })

}
const load = async (row, treeNode, resolve) => {
    let params = {
        parentId: row.id,
        fileName: props.fileName,
    }
    let res = await Api.select.query.post(params);
    dialogData.value = reportData.map(item => {
        props.mapping.forEach(ele => {
            item[ele.label] = item[ele.value]
            delete item[ele.value]
        })
        return item
    })
    resolve(res.reportData)
}
/**
 * 由于el-dialog的懒加载如果在挂载时直接拿去对话框里table的ref是获取不到的
 * 只有在open里才能获取！！！
 * 优化：每次打开对话框就会执行getTableData该怎样优化
 * 可能一：在对话框外的dom上放一个一样的elTable如tableSelect组件一样？？？
 */
const open = () => {
    Object.assign(formData.value, props.fieldMap)
    // formData.value = props.fieldMap
    // formKey.value+=1
    getInit()
}
/**判断数据状态
 * templateData为初始子表数据，当取消勾选某一条初始数据父组件可以接收到一条删除数据若再重新勾选会接受到一条新增数据
 * 优化？？？？
 */
const select = (rows, row) => {
    if (templateData.value.findIndex(item => item[props.defineProps.value] === row[props.defineProps.value]) == -1 || rows.findIndex(item => item[props.defineProps.value] === row[props.defineProps.value]) !== -1) {
        row.operationType = 'add'
    }
    else {
        let temp = templateData.value.find(item => item[props.defineProps.value] === row[props.defineProps.value])
        temp.operationType = 'delete'
        emit('deleteRow', temp)
    }
    let index = data.value.findIndex(item => item[props.defineProps.value] === row[props.defineProps.value])
    if (index == -1) {
        data.value.push(row)
        emit('selectRow',row)
    }
    else {
        data.value.splice(index, 1)
    }
}
/**
 * 当全部取消勾选时，勾选数组与当页数据进行对比 分为勾选在此页的数组与不在此页的数组进行操作。
 * 全部勾选只要要判断原始数据是否存在，不存在状态为add即可
 */
const selectAll = (rows) => {
    if (rows.length === 0) {
        let deleteArr = templateData.value.filter((item) => {
            return dialogData.value.some(ele => ele[props.defineProps.value] === item[props.defineProps.value])
        });
        deleteArr.forEach(row => {
            let temp = templateData.value.find(item => item[props.defineProps.value] === row[props.defineProps.value])
            temp.operationType = 'delete'
            emit('deleteRow', temp)
        })
        data.value = data.value.filter((item) => {
            return !dialogData.value.some(ele => ele[props.defineProps.value] === item[props.defineProps.value])
        })

    }
    else {
        rows.forEach(item => {
            if (templateData.value.findIndex(ele => ele[props.defineProps.value] === item[props.defineProps.value]) == -1) {
                item.operationType = 'add'
            }
            let index = data.value.findIndex(row => row[props.defineProps.value] === item[props.defineProps.value])
            if (index == -1) {
                data.value.push(item)
                emit('selectRow',row)
            }
        })
    }
}
const rowDel = (row, index) => {
    data.value.splice(index, 1)
    let temp = templateData.value.find(item => item[props.defineProps.value] === row[props.defineProps.value])
    if (temp) {
        temp.operationType = 'delete'
        emit('deleteRow', temp)
    }
}
const openDialog = () => {
    dialogVisible.value = true
}
defineExpose({ openDialog });
</script>

<style lang="less" scoped>
.ts-form-table {
    width: 100%;
}

.ts-form-table .ts-form-table-handle {
    text-align: center;
}

.ts-form-table .ts-form-table-handle span {
    display: inline-block;
}

.ts-form-table .ts-form-table-handle button {
    display: none;
}

.ts-form-table .hover-row .ts-form-table-handle span {
    display: none;
}

.ts-form-table .hover-row .ts-form-table-handle button {
    display: inline-block;
}

.sc-table-select__page {
    padding-top: 12px;
}

.tableselect {
    :deep(.el-input__wrapper) {
        padding-right: 1px;
    }

    :deep(.el-select__caret) {
        transform: rotateZ(0deg) !important;
        margin-left: 12px;
    }

    :deep(.el-input__suffix) {
        background-color: #f6f6f6;
        width: 40px;
    }
}

.icon {
    :deep(.el-input__wrapper) {
        padding-right: 1px;
        padding-left: 1px;
    }
}
</style>
